package bmaso.purest;

import java.io.IOException;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspTagException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.tagext.BodyTagSupport;

/**
 * <p>
 * Use this tag to create a "dispatcher" page -- a page which will route all REST
 * invocations to the appropriate purest service JSP page. Body content is a comma-
 * separated list of JSP URIs. Each of the named URIs should be a purest service
 * JSP page. The page containing this tag should only contain this tag, and nothing else.
 * </p>
 * 
 * <p>
 * For example:
 * </p>
 * 
 * <pre><tt><b>
 * <i>WAR/dispatcher.jsp:</i>
 * &gt;%@ taglib prefix="pr" uri="http://www.purest-tl.org/services" %>
 * &gt;pr:dispatcher>
 *   /WEB-INF/flights.jsp,
 *   /WEB-INF/reservations.jsp,
 *   /WEB-INF/timetables.jsp
 * &gt;/pr:dispatcher>
 * </b></tt></pre>
 * 
 * <p>
 * The dispatcher page above should be configured in web.xml to receive all REST invocations
 * intended for any one of the three purest service JSPs, like below. Note that this is the
 * <i>only</i> non-JSP configuration needed to get all your purest services working in J2EE.
 * </p>
 * 
 * <pre><tt><b>
 * <i>WAR/WEB-INF/web.xml</i>
 * ...
 * &gt;servlet>
 *   &gt;servlet-name>purest-dispatcher&gt;/servlet-name>
 *   &gt;jsp-file>/dispatcher.jsp&gt;/dispatcher.jsp>
 * &gt;/servlet>
 * 
 * ...
 * 
 * &gt;servlet-mapping>
 *   &gt;servlet-name>purest-dispatcher&gt;/servlet-name>
 *   &gt;servlet-mapping>/services/*&gt;/servlet-mapping>
 * &gt;/servlet-mapping>
 * 
 * ...
 * </b></tt></pre>
 * 
 * <p>
 * And that's it for modifying J2EE to get purest services working.
 * </p>
 */
public class DispatcherTag extends BodyTagSupport {
	public static final String CONTEXT_URI_ATTRIBUTE_NAME =
		"purest.dispatcher.context_uri";
		
	private static Pattern p = Pattern.compile("[\\s,]*([^\\s,]+)");
	
	private PageContext pc;
	
	@Override
	public int doEndTag() throws JspException {
		try {
			BodyContent bc = getBodyContent();
			String listOfServiceURIs = bc.getString();
			bc.clearBody();
			
			Matcher m = p.matcher(listOfServiceURIs);
			while(m.find()) {
				String resourcePath = m.group(1);
				Set<String> resourceSubPaths =
					(Set<String>)pc.getServletContext().getResourcePaths(resourcePath);
				for(String subPath : resourceSubPaths) {
					if(!subPath.endsWith("/")) {
						RequestDispatcher rd = pc.getServletContext().getRequestDispatcher(subPath);
						rd.include(pc.getRequest(), pc.getResponse());
						
						Boolean f = (Boolean)pc.findAttribute(RESTTagLibConstants.RESPONSE_GENERATED_REQUEST_ATTR);
						if(f != null && f.booleanValue()) {
							//...response was generated...
							pc.getResponse().setContentType((String)pc.getRequest().getAttribute(RESTTagLibConstants.RESPONSE_CONTENTTYPE_REQUEST_ATTR));
							bc.writeOut(getPreviousOut());
							break;
						} else {
							pc.getResponse().reset();
						}
					}
				}
			}
			
			return SKIP_BODY;
		} catch (IOException ioe) {
			throw new JspTagException(ioe);
		} catch (ServletException se) {
			throw new JspTagException(se);
		}
	}
	
	public void setPageContext(PageContext pc) {
		super.setPageContext(pc);
		this.pc = pc;
		
		HttpServletRequest request = (HttpServletRequest)pc.getRequest();
		String purestContextUri = request.getRequestURI().substring(request.getContextPath().length());
		
		if(request.getAttribute("javax.servlet.forward.request_uri") != null) {
			String requestUri = (String)request.getAttribute("javax.servlet.forward.request_uri");
			String contextPath = (String)request.getAttribute("javax.servlet.forward.context_path");
			purestContextUri = requestUri.substring(contextPath.length());
		} else if(request.getAttribute("javax.servlet.include.request_uri") != null) {
			String requestUri = (String)request.getAttribute("javax.servlet.include.request_uri");
			String contextPath = (String)request.getAttribute("javax.servlet.include.context_path");
			purestContextUri = requestUri.substring(contextPath.length());
		}
		
		request.setAttribute(CONTEXT_URI_ATTRIBUTE_NAME, purestContextUri);
	}
}
